/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine - graphics
// Copyright (c) 2014.  All Rights Reserved
//
// File:		AEBaseVideoDevice.h
// Author:		Gianluca Belardelli
// Date:		11/06/2014
//
/////////////////////////////////////////////////////////////////////////
#ifndef _AEBASEVIDEODEVICE_H_
#define _AEBASEVIDEODEVICE_H_

/// \brief Base class for managing video-related functions.
/// This class offers video related-functions like device and video initialization, buffer swapping,
/// window creation etc.
/// The Vision Engine's VisVideo_cl class is derived from this class. For most applications, it is sufficient to work with the
/// higher-level functionality exposed by the VisVideo_cl class (e.g. SetMode) rather than directly calling into the low-level
/// methods of the VVideo class.
class AEBaseVideoDevice
{
// Members
protected:
#if defined( AE_PLATFORM_ANDROID ) || defined( AE_PLATFORM_IOS )
	static AEBOOL32	m_bPVRTCSupported;
	static AEBOOL32	m_bETCSupported;
	static AEBOOL32	m_bPackedDepthStencilSupported;
	static AEINT32	m_iMaxGLTextureSize;
#endif

#if defined( AE_PLATFORM_ANDROID )
	static AEVideoConfig m_AndroidGLES2Config;
#endif

	static AEBOOL32  		m_bInitialized;
	static AEUINT32			m_uiLastErrorCode;
	//static AEVideoConfig	m_vcCurrentConfig;

// Methods
protected:
#ifdef WIN32
	#if defined(AE_OPENGL)
  		static AE_DLLIMPEXP AEBOOL32 InitializeOpenGL( AEVideoConfig &oglConfig );
  		static AE_DLLIMPEXP AEBOOL32 DeInitializeOpenGL( void );
	#endif
	#if defined(AE_DX9)
  		static AE_DLLIMPEXP AEBOOL32 InitializeDirect3D( AEVideoConfig &dx9Config );
  		static AE_DLLIMPEXP AEBOOL32 DeInitializeDirect3D();
  		static AE_DLLIMPEXP AEBOOL32 GetCurrentAdapterMode( AEINT32 iAdapter, AEVideoMode &Mode );
	#endif	
#endif	

public:
	AE_FORCEINLINE virtual ~AEBaseVideoDevice( void ) {} //Nothing to do here  
	
	/// \brief For devices supporting querying device display resolutions, this function
	/// returns the display resolution in dots per inch (dpi).
	/// Supported on Android, iOS, and Windows RT. Returns a default value of 96 on other platforms, which is the value used by Windows.
	AE_DLLIMPEXP AEFLOAT32 GetDeviceDpi( void ) const;
	
#ifdef WIN32
	/// \brief Returns the handle of the application instance. Windows PCs only.
	/// \return HINSTANCE hInstance: Handle to the application instance
	/// \note This function is only valid on Windows. It would not make sense to use it on any other
	///   platform. Since you don't need to define WinMain, this function can be useful if
	///   you want to perform e.g. Windows API calls.
	static AE_DLLIMPEXP HINSTANCE GetAppInstance( void );
	
	static AE_DLLIMPEXP DEVMODEA GetAdapterMode( AEINT32 iAdapter );
#endif

#if defined( AE_PLATFORM_ANDROID ) || defined( AE_PLATFORM_IOS )
	#if defined AE_OPENGLES2
		/// \brief Initializes OpenGLES 2.0. This function needs to be called before calling InitializeScreen().
		/// This method is only available on OpenGLES 2.0 platforms, e.g. Android and iOS.
		static AE_DLLIMPEXP AEBOOL32 InitializeGLES2( const AEVideoConfig &gles2Config );
	
		/// \brief Deinitializes OpenGLES 2.0. Only available on OpenGLES 2.0 platforms, e.g. Android and iOS.
		static AE_DLLIMPEXP AEBOOL32 DeInitializeGLES2( void );
	#elif defined AE_OPENGLES3
		/// \brief Initializes OpenGLES 2.0. This function needs to be called before calling InitializeScreen().
		/// This method is only available on OpenGLES 2.0 platforms, e.g. Android and iOS.
		static AE_DLLIMPEXP AEBOOL32 InitializeGLES3( const AEVideoConfig &gles2Config );
	
		/// \brief Deinitializes OpenGLES 2.0. Only available on OpenGLES 2.0 platforms, e.g. Android and iOS.
		static AE_DLLIMPEXP AEBOOL32 DeInitializeGLES3( void );
	#endif	
	/// \brief Returns whether PVR textures are supported on the OpenGL ES 2.0 device. 
	/// Needs to be called after screen initialization.
	static AE_FORCEINLINE AEBOOL32 IsPVRTCSupported( void ) { return m_bPVRTCSupported; }
	
	/// \brief Returns whether ETC textures are supported on the OpenGL ES 2.0 device. 
	/// Needs to be called after screen initialization.
	static AE_FORCEINLINE AEBOOL32 IsETCSupported( void ) { return m_bETCSupported; }
	
	/// \brief Returns whether the packed depth-stencil extension is supported on the OpenGL ES 2.0 device. 
	/// Needs to be called after screen initialization.
	/// Vision will automatically use packed depth-stencil targets if they are supported. They are required for shadow map support.
	/// \return AEBOOL32: true if packed depth-stencil is supported.
	static inline AEBOOL32 IsPackedDepthStencilSupported( void ) { return m_bPackedDepthStencilSupported; }
	
	/// \brief Returns the max texture size supported by the devices.
	/// \return
	///   AEINT32: The max texture size (width / height) of a texture in pixels supported on the device.
	static inline AEINT32 GetMaxTextureSizeSupported( void ) { return m_iMaxGLTextureSize; }
	
	#if defined( AE_PLATFORM_IOS )
		static AE_DLLIMPEXP AEVideoConfig *GetVideoConfig( void ) { return &m_IOSGLES2Config; }
	#else
		static AE_DLLIMPEXP AEVideoConfig *GetVideoConfig( void ) { return &m_AndroidGLES2Config; }
	#endif
	
#endif

	/// \brief Initializes the device context.
	/// This method has to be called in order to create a device context that can be rendered to. The
	/// settings of this device context are specified through the AEVideoConfig structure passed to this
	/// method. InitializeScreen() will allocate front and back buffers, command buffer structures, and
	/// various platform-specific data structures. On Windows, it will additionally perform the following operations:
	/// \li It adjusts the screen resolution if the mode is a full-screen mode
	/// \li If the AEVideoConfig structure does not contain a window handle, a window is created (and
	///   stored in the AEVideoConfig structure)
	/// \li The context configuration data (e.g. pixel format) is set, and a swap chain is
	///   created
	/// \param vc Reference to a AEVideoConfig structure describing the mode to be initialized
	/// \return
	///   AEBOOL32: true if the initialization succeeded, otherwise false. Use VVideo::GetLastError to get
	///   additional information.
	static AE_DLLIMPEXP AEBOOL32 InitializeScreen( AEVideoConfig &vc );

	/// \brief DeInitializes the device context.
	/// Memory allocated by InitializeScreen is freed again.
	/// \param vc Reference to the AEVideoConfig structure that was previously used to initialize the screen.
	/// \return
	///   AEBOOL32: true if the deinitialization succeeded, otherwise false. Use VVideo::GetLastError to get
	///   additional information.
	static AE_DLLIMPEXP AEBOOL32 DeInitializeScreen( AEVideoConfig &vc );

	/// \brief Restores the specified adapter's original screen mode.
	/// The original screen mode is the screen mode that was set before the last
	/// InitializeScreen call. Only relevant on Windows PCs.
	/// This method is called by DeInitializeScreen. It is usually not necessary to call this function directly.
	/// \param iAdapter Index of the adapter/device to be used
	/// \return
	///   AEBOOL32: true if restoring succeeded, otherwise false. Use VVideo::GetLastError to get additional
	///   information.
	static AE_DLLIMPEXP AEBOOL32 RestoreScreen( AEINT32 nAdapter = 0 );

	/// \brief Returns a string containing the description of the specified adapter.
	/// On console platforms, iAdapter has to be 0.
	/// \param iAdapter Index of the adapter/device to be used
	/// \return
	///   VString: description of the specified adapter.
	static AE_DLLIMPEXP char *GetAdapterDesc( AEINT32 nAdapter = 0 );
	
	/// \brief Changes the settings of an already initialized screen mode on the fly.
	/// The properties of the AEVideoConfig structure that are actually taken into account when
	/// switching screen modes may vary from platform to platform. Typically, m_iXRes, m_iYRes,
	/// m_bFullScreen, and m_iRefreshRate will be taken into account.
	/// This feature is only supported on Windows PCs and Xbox360.
	/// \note
	///   This method internally resets the device, which requires ALL graphics resources to be
	///   destroyed. When using this low-level function instead of Vision::Video.ChangeScreenResolution(),
	///   you need to take care of this yourself (otherwise, you will get an assertion).
	/// \param vc New properties for the screen mode
	/// \return
	///   AEBOOL32: true if changing the screen settings succeeded, otherwise false. Use VVideo::GetLastError to
	///   get additional information.
	static AE_DLLIMPEXP AEBOOL32 ChangeScreenSettings( AEVideoConfig &vc );
	
	/// \brief Returns the index of the default display device. Will be zero on all devices with only one monitor.
	/// DX9: Index of the default monitor in m_MonitorList, which is in the order determined by windows.
	/// DX11: The default monitor is always 0 as iterated by IDXGIAdapter::EnumOutputs.
	/// Always 0 on non-Windows platforms.
	/// \return AEINT32: index of the default system adapter.
	static AE_DLLIMPEXP AEINT32 GetDefaultDisplayDevice( void );
	
	/// \brief Returns the number of supported devices on the system
	/// The devices (adapters) can later on be accessed through their index.
	/// \return
	///   AEBOOL32: true if changing the screen settings succeeded, otherwise false. Use VVideo::GetLastError to
	///   get additional information.
	static AE_DLLIMPEXP AEINT32 GetAdapterCount( void );
	
	/// \brief Returns the number of supported display modes for a specific device.
	/// Only adapters with the specified front buffer color depth will be counted.
	/// Typically, supported front buffer color depths are 16 and 32 bits.
	/// \param iAdapter Index of the adapter/device to be used. Always 0 on non-Windows platforms.
	/// \param iFrontBufferBPP Front buffer color depth
	/// \return AEINT32: Number of supported adapter modes
	static AE_DLLIMPEXP AEINT32 GetAdapterModeCount( AEINT32 nAdapter, AEINT32 nFrontBufferBPP );
	
	/// \brief Enumerates all supported adapter modes matching the specified settings.
	/// The adapters supported the specified device with the specified front buffer color depth will
	/// be enumerated.
	/// Typically, supported front buffer color depths are 16 and 32 bits.
	/// \param iAdapter Index of the adapter/device to be used. Always 0 on non-Windows platforms.
	/// \param iFrontBufferBPP Front buffer color depth
	/// \param pModes An array of AEVideoMode structures containing the supported video modes. You have to take
	///   care of the memory handling and ensure that the array is large enough to contain all video modes.
	/// \return AEINT32: Number of supported adapter modes
	static AE_DLLIMPEXP AEINT32  EnumAdapterModes( AEINT32 nAdapter, AEINT32 nFrontBufferBPP, AEVideoMode *lpModes );
	
	/// \brief Performs a present operation (buffer flipping or copying)
	/// In order to display the rendered content, an present operation will be performed, ie. switching
	/// front and back buffer.
	/// The actual present operation performed (eg. flip vs. copy) is handled transparently.
	/// \param vc Reference to the AEVideoConfig structure that was previously used to initialize the screen.
	/// \return
	///   AEBOOL32 bDeviceLost: false if the device is lost, true if this is not the case. For semantics
	///   regarding the device lost state, please refer to the DirectX9 SDK documentation. Note that
	///   this state can only be returned on WIN32 DX9.
	static AE_DLLIMPEXP AEBOOL32 Present( AEVideoConfig &vc );
	
	/// \brief Returns the system's default color depth
	/// On WIN32 systems, this is the desktop color depth.
	/// On Xbox360, this will always be 32.
	/// On PS3, this will always be 32.
	/// \return AEINT32: Default color depth.
	static AE_DLLIMPEXP AEINT32 GetDefaultBPP( void );
	
	/// \brief Indicates whether the passed texture format is supported by a specific video device. From the AEVideoConfig parameter, only the adapter information is used.
	static AE_DLLIMPEXP AEBOOL32 IsTextureFormatSupported( AETextureFormat eFormat, const AEVideoConfig &videoConfig );
	
	/// \brief Indicates whether the passed render target format is supported by a specific video device (when creating a renderable texture)
	/// \param eFormat The texture format that should be queried for render target support.
	/// \param videoConfig Only the adapter information inside this AEVideoConfig is used.
	/// \note
	///   If a renderable texture with bRenderTargetOnly=false is created, IsTextureFormatSupported() should also be called in order
	///   to check whether the texture format can also be sampled.
	static AE_DLLIMPEXP AEBOOL32 IsRenderTargetFormatSupported( AETextureFormat eFormat, const AEVideoConfig &videoConfig );
	
	/// \brief Indicates whether the passed texture format is supported by a specific video device (when creating a renderable texture)
	/// \param eFormat The texture format that should be queried for depth stencil support.
	/// \param videoConfig Only the adapter information inside this AEVideoConfig is used.
	/// \note
	///   If a renderable texture with bRenderTargetOnly=false is created, IsTextureFormatSupported() should also be called in order
	///   to check whether the texture format can also be sampled.
	static AE_DLLIMPEXP AEBOOL32 IsDepthStencilFormatSupported(AETextureFormat eFormat, const AEVideoConfig &videoConfig);
	
	/// \brief Indicates whether the passed texture format supports linear filtering by a specific video device (in the pixel shader).
	/// \param eFormat The texture format that should be queried for linear filtering support.
	/// \param videoConfig
	///   Only the adapter information inside this AEVideoConfig is used.
	static AE_DLLIMPEXP AEBOOL32 IsTextureFilteringSupported(AETextureFormat eFormat, const AEVideoConfig &videoConfig);

};

#endif // _AEBASEVIDEODEVICE_H_
